# -*- coding: utf-8 -*-
import sqlalchemy as sa

from bopress import metas
from bopress.model import Terms, TermTaxonomy, TermRelationships, TermTaxonomyMeta
from bopress.orm import SessionFactory, pk, get_ref_column

__author__ = 'yezang'


def add_term(name, slug):
    if not name or not slug:
        return None
    s = SessionFactory.session()
    term = s.query(Terms).filter(Terms.slug == slug).one_or_none()
    if not term:
        term = Terms()
        term.term_id = pk()
        term.name = name
        term.slug = slug
        s.add(term)
        s.commit()
    else:
        term.name = name
        s.commit()
    return term


def add_taxonomy(term_id, taxonomy, parent_id='', description='', position=0):
    if not term_id or not taxonomy:
        return None
    s = SessionFactory.session()
    tt = s.query(TermTaxonomy).filter(TermTaxonomy.term_id == term_id) \
        .filter(TermTaxonomy.taxonomy == taxonomy).one_or_none()
    if not tt:
        tt = TermTaxonomy()
        tt.term_taxonomy_id = pk()
        tt.term_id = term_id
        tt.taxonomy = taxonomy
        tt.parent_id = parent_id
        tt.description = description
        tt.position = position
        s.add(tt)
        s.commit()
    return tt


def update_taxonomy(term_taxonomy_id, term_id, taxonomy, parent_id='', description='', position=0):
    if not term_taxonomy_id or not term_id or not taxonomy:
        return False, "Error", ""
    s = SessionFactory.session()
    num = s.query(TermTaxonomy).filter(TermTaxonomy.term_id == term_id) \
        .filter(TermTaxonomy.taxonomy == taxonomy) \
        .filter(TermTaxonomy.term_taxonomy_id != term_taxonomy_id) \
        .count()
    if num > 0:
        return False, "Duplicate", ""
    tt = s.query(TermTaxonomy).get(term_taxonomy_id)
    if tt:
        tt.term_id = term_id
        tt.taxonomy = taxonomy
        tt.parent_id = parent_id
        tt.description = description
        tt.position = position
        s.commit()
        return True, "OK", tt
    else:
        return False, "Failure", ""


def get_term_taxonomys(taxonomy, term_taxonomy_id="", use_tree=True, with_unnamed=False):
    ds = list()
    if not taxonomy:
        return ds
    unnamed_taxonomy_id = ""
    if not with_unnamed:
        unnamed_taxonomy_id = get_unnamed_term_taxonomy_id(taxonomy)
    s = SessionFactory.session()
    q = s.query(TermTaxonomy.term_taxonomy_id, TermTaxonomy.parent_id,
                Terms.name, Terms.slug, TermTaxonomy.description, TermTaxonomy.position) \
        .select_from(TermTaxonomy) \
        .outerjoin(Terms, Terms.term_id == TermTaxonomy.term_id) \
        .filter(TermTaxonomy.taxonomy == taxonomy)
    if unnamed_taxonomy_id:
        q = q.filter(TermTaxonomy.term_taxonomy_id != unnamed_taxonomy_id)
    if term_taxonomy_id:
        one = q.filter(TermTaxonomy.term_taxonomy_id == term_taxonomy_id).first()
        if one:
            ds.append(one)
        return ds
    return q.order_by(TermTaxonomy.position.asc()).all()


def delete_taxonomy(term_taxonomy_id):
    if not term_taxonomy_id:
        return False, "Error"
    s = SessionFactory.session()
    term_id = s.query(TermTaxonomy.term_id).filter(TermTaxonomy.term_taxonomy_id == term_taxonomy_id).scalar()
    num = s.query(TermTaxonomy).filter(TermTaxonomy.term_id == term_id).count()
    s.query(TermTaxonomy).filter(TermTaxonomy.term_taxonomy_id == term_taxonomy_id).delete()
    if num == 0:
        s.query(Terms).filter(Terms.term_id == term_id).delete()
    s.commit()
    return True, "OK"


def term_taxonomy_exists(taxonomy):
    """
    每个分类都会默认创建一个未命名的分类、所以此函数可以用来判断``taxonomy``的合法性。
    :param taxonomy:
    :return:
    """
    if not taxonomy:
        return False
    s = SessionFactory.session()
    num = s.query(TermTaxonomy).filter(TermTaxonomy.taxonomy == taxonomy).count()
    if num > 0:
        return True
    return False


def create_unnamed_taxonomy(taxonomy):
    """
    创建未命名分类，此分类可不显示
    :param taxonomy:
    :return:
    """
    if not taxonomy:
        return None
    if term_taxonomy_exists(taxonomy):
        return None
    t = add_term('未命名', 'unnamed')
    if t:
        tt = add_taxonomy(t.term_id, taxonomy)
        if tt:
            metas.save_termtaxonomy_metas(tt.term_taxonomy_id, "bo_unnamed", True)
        return tt
    return None


def create_default_taxonomy(name, slug, taxonomy):
    """
    创建缺省分类、此分类不能删除、此函数可在插件加载时调用
    :param name:
    :param slug:
    :param taxonomy:
    :return: `.model.TermTaxonomy` or `None`
    """
    if not taxonomy:
        return None
    create_unnamed_taxonomy(taxonomy)
    t = add_term(name, slug)
    if t:
        tt = add_taxonomy(t.term_id, taxonomy)
        if tt:
            metas.save_termtaxonomy_metas(tt.term_taxonomy_id, "bo_default", True)
        return tt
    return None


def create_termtaxonomy(name, slug, taxonomy, parent_id='', description='', position=0):
    """
    创建分类
    :param position:
    :param description:
    :param parent_id:
    :param name:
    :param slug:
    :param taxonomy:
    :return:
    """
    if not taxonomy:
        return False, None
    t = add_term(name, slug)
    if t:
        tt = add_taxonomy(t.term_id, taxonomy, parent_id, description, position)
        return True, tt
    return False, None


def update_termtaxonomy(term_taxonomy_id, name, slug, taxonomy, parent_id='', description='', position=0):
    """
    创建分类
    :param term_taxonomy_id:
    :param position:
    :param description:
    :param parent_id:
    :param name:
    :param slug:
    :param taxonomy:
    :return:
    """
    if not taxonomy:
        return False, None
    t = add_term(name, slug)
    if t:
        tt = update_taxonomy(term_taxonomy_id, t.term_id, taxonomy, parent_id, description, position)
        return tt
    return False, None


def get_unnamed_term_taxonomy_id(taxonomy):
    """
    ``bo_unnamed`` 未命名分类与 ``bo_default`` 缺省分类都不能删除，前者可不显示
    :param taxonomy:
    :return:
    """
    if not taxonomy:
        return ""
    s = SessionFactory.session()
    ds = s.query(TermTaxonomy.term_taxonomy_id, TermTaxonomyMeta.meta_value) \
        .select_from(TermTaxonomyMeta) \
        .outerjoin(TermTaxonomy) \
        .filter(TermTaxonomy.taxonomy == taxonomy) \
        .filter(TermTaxonomyMeta.meta_key == "bo_unnamed").all()
    for r in ds:
        if r[1]:
            return r[0]
    return ""


def get_default_term_taxonomy_idset(taxonomy):
    """
    ``bo_unnamed`` 未命名分类与 ``bo_default`` 缺省分类都不能删除，前者可不显示
    :param taxonomy:
    :return:
    """
    rs = set()
    if not taxonomy:
        return rs
    s = SessionFactory.session()
    ds = s.query(TermTaxonomy.term_taxonomy_id, TermTaxonomyMeta.meta_value) \
        .select_from(TermTaxonomyMeta) \
        .outerjoin(TermTaxonomy) \
        .filter(TermTaxonomy.taxonomy == taxonomy) \
        .filter(TermTaxonomyMeta.meta_key == "bo_default").all()
    for r in ds:
        if r[1]:
            rs.add(r[0])
    return rs


def add_term_relationships(term_taxonomy_id, model_object):
    cls_name = "{0}.{1}".format(model_object.__class__.__module__, model_object.__class__.__name__)
    pk_v = str(getattr(model_object, get_ref_column(type(model_object)).key))
    s = SessionFactory.session()
    num = s.query(TermRelationships) \
        .filter(TermRelationships.term_taxonomy_id == term_taxonomy_id) \
        .filter(TermRelationships.object_id == pk_v) \
        .filter(TermRelationships.cls_name == cls_name).count()
    if num > 0:
        return False, None
    tr = TermRelationships()
    tr.object_id = pk_v
    tr.cls_name = cls_name
    tr.term_taxonomy_id = term_taxonomy_id
    s.add(tr)
    s.commit()
    return True, tr


def update_term_relationships(term_taxonomy_id, current_term_taxonomy_id, model_object):
    if not term_taxonomy_id or not model_object:
        return False, None
    cls_name = "{0}.{1}".format(model_object.__class__.__module__, model_object.__class__.__name__)
    pk_v = str(getattr(model_object, get_ref_column(type(model_object)).key))
    s = SessionFactory.session()
    tr = s.query(TermRelationships) \
        .filter(TermRelationships.term_taxonomy_id == current_term_taxonomy_id) \
        .filter(TermRelationships.object_id == pk_v) \
        .filter(TermRelationships.cls_name == cls_name).one_or_none()
    if tr:
        tr.object_id = pk_v
        tr.cls_name = cls_name
        tr.term_taxonomy_id = term_taxonomy_id
        s.add(tr)
        s.commit()
    else:
        tr = TermRelationships()
        tr.object_id = pk_v
        tr.cls_name = cls_name
        tr.term_taxonomy_id = term_taxonomy_id
        s.add(tr)
        s.commit()
    return True, tr


# delete require a default term_taxonomy_id.


# 权限子查询与分类子查询可以合并起来查询出``model_cls``对象结合

def get_term_relationships_by_taxonomy(taxonomy, model_cls):
    cls_name = "{0}.{1}".format(model_cls.__module__, model_cls.__name__)
    pk_column = get_ref_column(model_cls)
    s = SessionFactory.session()
    return s.query(Terms.name, Terms.slug, TermTaxonomy.term_id,
                   sa.cast(TermRelationships.object_id, pk_column.type).label("object_id")) \
        .select_from(TermRelationships) \
        .outerjoin(TermTaxonomy, TermTaxonomy.term_taxonomy_id == TermRelationships.term_taxonomy_id) \
        .outerjoin(Terms, Terms.term_id == TermTaxonomy.term_id) \
        .filter(TermRelationships.cls_name == cls_name).filter(TermTaxonomy.taxonomy == taxonomy).subquery()


def get_term_relationships_by_id(term_taxonomy_id, model_cls):
    cls_name = "{0}.{1}".format(model_cls.__module__, model_cls.__name__)
    pk_column = get_ref_column(model_cls)
    s = SessionFactory.session()
    return s.query(Terms.name, Terms.slug, TermTaxonomy.term_id,
                   sa.cast(TermRelationships.object_id, pk_column.type).label("object_id")) \
        .select_from(TermRelationships) \
        .outerjoin(TermTaxonomy, TermTaxonomy.term_taxonomy_id == TermRelationships.term_taxonomy_id) \
        .outerjoin(Terms, Terms.term_id == TermTaxonomy.term_id) \
        .filter(TermRelationships.cls_name == cls_name) \
        .filter(TermTaxonomy.term_taxonomy_id == term_taxonomy_id).subquery()
